<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://cdn.staticfile.org/vue/3.0.5/vue.global.js"></script>
</head>

<body>
    <div id="app" class="demo">
        <div>{{reactiveInfo}}</div>
        <ol>
            <li>{{reactiveInfo.name}}</li>
            <li>{{reactiveInfo.age}}</li>
        </ol>
        <div>useDebounceRef num: {{num}}  <button @click="my_print">设置值</button></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
    </div>
</body>
<script>

    //reactive, toRefs, toRef, isRef, unref, customRef, shallowRef, triggerRef 
    const HelloVueApp = {
        data() {
            return {
                num:1,
            }
        },
        methods:{
            my_print(){
               let refNum = this.useDebounceRef(this.num);
               refNum.value = 5;
               console.log("refNum : "+refNum.value);
            }
        },
        setup() {
            // 1. toRefs 函数可以将一个 reactive 函数定义的响应式代理对象转换为一个包含 ref 对象属性的普通对象
            const reactiveInfo = Vue.reactive({
                name: 'zy',
                age: 22
            })
            const toRefsTest = Vue.toRefs(reactiveInfo)
            console.log('toRefs  :' + toRefsTest)
            console.log('toRefs  :' + toRefsTest.age.value)
            console.log('toRefs  :' + toRefsTest.name.value)

            // 2. toRef 函数用于转换 reactive 定义的响应式代理对象中的某一属性为 ref 对象
            const name = Vue.toRef(reactiveInfo, 'name') // 将 name 属性转换为 ref
            console.log('toRef  :' + name.value)

            // 3. isRef 函数可以用于判断某个值是否为 ref 对象
            console.log('isRef  :' + Vue.isRef(name)) //true

            // 4. unref 函数的参数如果为 ref 代理对象则返回内部 value 值，否则返回参数
            console.log('unref  :' + Vue.unref(name), Vue.unref(123))

            // 5. customRef 函数可以创建一个自定义的 ref ，接收一个工厂函数作为参数
            // 该工厂函数接收 track 和 trigger 两个函数作为参数并返回一个带有 get 和 set 方法的对象并对其依赖项和更新触发进行控制（如自定义的防抖ref）
            // 自定义 ref 响应式变量
            const MyRef = Vue.customRef((track, trigger) => {
                let value
                return {
                    get() {
                        track()
                        console.log('customRef  :' + '我被读取了')
                        return value
                    },
                    set(newValue) {
                        console.log('customRef  :' + '我被赋值了')
                        value = newValue
                        trigger()
                    }
                }
            })
            MyRef.value = 123
            console.log('unref  :' + Vue.unref(MyRef))

            // 防抖功能的 ref 响应式变量
            const useDebounceRef = (value, delay = 3000) => {
                let timer
                return Vue.customRef((track, trigger) => {
                    return {
                        get() {
                            // 获取时收集依赖并返回对象
                            console.log("^^^^^^^^^^^^^^^^");
                            track()
                            return value
                        },
                        set(newValue) {
                            // 触发赋值时清除计时器并重新开启计时器
                            clearTimeout(timer)
                            timer = setTimeout(() => {
                                console.log("******************");
                                value = newValue ;
                                // 调用更新依赖
                                trigger()
                            }, delay)
                        }
                    }

                })
            }

            //
            // 6. shallowRef 函数可以创建一个浅层 ref 响应式代理对象
            const useShallowRef = Vue.shallowRef({
                name: 'zy',
                age: 22
            })

            useShallowRef.value.age = 23 //更改name属性则不会触发响应式
            console.log("useShallowRef :"+useShallowRef.value.age);

            // 7. triggerRef 函数可以手动强制触发依赖于一个浅层 ref 的副作用（通常在对浅引用内部值进行深度变更后使用）
            Vue.triggerRef(useShallowRef) //这将触发刚才对于 shallowRef 浅层响应式对象的响应式副作用

            return {
                reactiveInfo,
                useDebounceRef,
                toRefsTest,

            }
        }
    }
    Vue.createApp(HelloVueApp).mount('#app')
</script>

</html>